from django.shortcuts import render
from web.utils.views import LoginRequiredMixin, LoginRequiredJSONMixin
from django.views import View
from django_redis import get_redis_connection
from decimal import Decimal
import json
from django import http
from django.utils import timezone
from django.db import transaction

from users import constants
from users.models import Address
from goods.models import SKU
from orders.models import OrderInfo, OrderGoods
from web.utils.response_code import RETCODE
from django.core.paginator import Paginator, EmptyPage


# Create your views here.


class OrderSuccessView(LoginRequiredMixin, View):
    """递交订单成功的页面"""
    def get(self, request):
        """提交订单成功页面"""
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }

        return render(request, 'order_success.html', context)

class OrderCommitView(LoginRequiredJSONMixin, View):
    """递交订单"""

    def post(self, request):
        """保存订单的基本信息和商品信息"""

        print(1)

        # 接受参数
        json_dict = json.loads(request.body.decode())
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('缺少必传参数')
            # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return http.HttpResponseForbidden('参数address_id错误')

        # 判断pay_method是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('参数pay_method错误')

        # 事务使用
        with transaction.atomic():
            # 在数据库操作前需要指定保存点（数据库最初的状态）
            save_id = transaction.savepoint()

            # 暴力回滚
            try:
                # 获取登录用户
                user = request.user

                # 获取订单编号：时间+用户id(补位)
                order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)

                # 保存订单基本信息(一)
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                # 保存订单商品信息(多)
                # 查询redis购物车中被勾选的商品
                redis_conn = get_redis_connection('carts')
                # 所有购物车数据，包含勾选与未勾选 {b'1':b'1' ,...}
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                # 被勾选的商品sku_id： [b'1']
                redis_selected = redis_conn.smembers('selected_%s' % user.id)
                # 构造购物车中被勾选的商品的字典/数据
                new_cart_dict = {}
                for sku_id in redis_selected:
                    new_cart_dict[int(sku_id)] = int(redis_cart[sku_id])

                # 获取被勾选的商品的sku_id
                sku_ids = new_cart_dict.keys()
                for sku_id in sku_ids:

                    # 每个商品都有下单的机会，直到库存不足为止
                    while True:
                        # 读取商品id
                        sku = SKU.objects.get(id=sku_id)  # 查询商品和库存信息时，不能出现缓存，所以不用filter(id__in==sku_ids)

                        # 获取原始的库存和销量
                        origin_stock = sku.stock
                        origin_sales = sku.sales

                        # 获取要提交订单的商品的数量
                        sku_count = new_cart_dict[sku.id]
                        # 判断商品数量是否大于库存，如果大于，响应库存不足
                        if sku_count > origin_stock:
                            # 库存不足，回滚
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # # 模拟网络延迟
                        # import time
                        # time.sleep(7)

                        # SKU 减库存，加销量
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()

                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 如果在更新数据时，原始数据变化了，返回0，表示有资源抢夺
                        if result == 0:
                            # 库存10个，要买1个，但是在下单时，有资源抢夺，被买走1个，剩下8个，如果库存满足，继续下单，直到库存不足为止
                            # return http.JsonResponse('下单失败')
                            continue

                        # SPU 加销量
                        sku.spu.sales += sku_count
                        sku.spu.save()

                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )

                        # 累加订单商品的数量和总价到基本信息表里
                        order.total_count += sku_count
                        order.total_amount += sku_count * sku.price

                        # 下单成功，记得Break
                        break

                # 再加最后的运费
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

            # 数据库操作成功，明显的提交一次事务
            transaction.savepoint_commit(save_id)

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'order_id': order_id})


class OrderSettlementView(LoginRequiredMixin, View):
    """"结算订单"""
    def get(self, request):
        """查询并展示要结算的订单数据"""
        # 获取登录用户
        user = request.user

        # 查询用户收货地址: 查询登录用户没有被删除的收货地址
        try:
            addresses = Address.objects.filter(user=user, is_deleted=False)
        except Exception as e:
            # 如果没有查询出地址，可以编辑收货地址
            addresses = None

        # 查询redis购物车中被勾选的商品
        redis_conn = get_redis_connection('carts')
        # 所有购物车数据，包含勾选与未勾选 {b'1':b'1' ,...}
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        # 被勾选的商品sku_id： [b'1']
        redis_selected = redis_conn.smembers('selected_%s' % user.id)
        # 构造购物车中被勾选的商品的字典/数据
        new_cart_dict = {}
        for sku_id in redis_selected:
            new_cart_dict[int(sku_id)] = int(redis_cart[sku_id])

        # 获取被勾选的商品的sku_id
        sku_ids = new_cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)

        total_count = 0
        total_amount = Decimal(0.00)
        # 遍历skus，给每个sku补充count(数量)，amount(小计)
        for sku in skus:
            sku.count = new_cart_dict[sku.id]
            sku.amount = sku.price * sku.count  # Decimal类型

            total_count += sku.count
            total_amount += sku.amount  # 类型不同，不能运算

        # 指定默认的邮费
        freight = Decimal(10.00)

        # 构造上下文
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
        }

        return render(request, 'place_order.html', context)


class UserOrderInfoView(LoginRequiredMixin, View):
    """我的订单"""

    def get(self, request, page_num=1):
        """提供我的订单页面"""

        user = request.user
        # 查询订单
        orders = user.orderinfo_set.all().order_by("-create_time")
        # 遍历所有订单
        for order in orders:
            # 绑定订单状态
            order.status_name = OrderInfo.ORDER_STATUS_CHOICES[order.status-1][1]
            # 绑定支付方式
            order.pay_method_name = OrderInfo.PAY_METHOD_CHOICES[order.pay_method-1][1]
            order.sku_list = []
            # 查询订单商品
            order_goods = order.skus.all()
            # 遍历订单商品
            for order_good in order_goods:
                sku = order_good.sku
                sku.count = order_good.count
                sku.amount = sku.price * sku.count
                order.sku_list.append(sku)

        print("订单载入成功")

        # 分页
        page_num = int(page_num)
        try:
            print("订单打印")
            paginator = Paginator(orders, constants.ORDERS_LIST_LIMIT)
            page_orders = paginator.page(page_num)
            total_page = paginator.num_pages
            print("订单共：",end='')
            print(total_page,end='页')
        except EmptyPage:
            return http.HttpResponseNotFound('订单不存在')

        context = {
            "page_orders": page_orders,
            'total_page': total_page,
            'page_num': page_num,
        }
        return render(request, "user_center_order.html", context)